package com.lion.common.spring.enhancers.advices;

import com.chris.dev.base.libs.v1.http.common.N;
import com.chris.dev.base.libs.v1.http.protocols.HttpHeader;
import com.chris.dev.base.libs.v1.http.protocols.HttpRequest;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.lion.common.base.contexts.CommonRequestContextHolder;
import com.lion.common.base.exceptions.CommonException;
import com.lion.common.base.json.GsonFactory;
import com.lion.common.spring.enhancers.helpers.RequestBodyDetectionHelper;
import com.lion.common.spring.enhancers.helpers.SimpleGenericResolver;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import java.io.IOException;
import java.lang.reflect.Type;

/**
 * 自定义RequestBodyAdvice，用于提取请求体中的参数
 *
 * @author Chris Chan
 * @date 2023/12/1 14:23
 * 从HttpRequest中提取参数
 */
@ControllerAdvice
public class HttpRequestCommonExtractAdvice implements RequestBodyAdvice {
    @Autowired
    Gson gson;

    @Override
    public boolean supports(MethodParameter methodParameter, Type targetType,
                            Class<? extends HttpMessageConverter<?>> converterType) {
        // 只处理特定类型的参数
        //return methodParameter.hasParameterAnnotation(RequestBody.class);
        return RequestBodyDetectionHelper.hasRequestBodyAnnotation(methodParameter);
    }

    @Override
    public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
        byte[] payload = StreamUtils.copyToByteArray(inputMessage.getBody());

        // 原始请求体
        String srcBodyJson = new String(payload);
        System.out.println("srcBodyJson:\n" + srcBodyJson);

        // 获取真实的参数类
        Class<?> resolveParameterClass = SimpleGenericResolver.resolveParameterClass(parameter, targetType.getClass());

        // 获取严格模式的GSON实例，严格检查参数
        Gson strictGson = GsonFactory.getStrictGson();

        // 尝试解析
        HttpRequest<?> httpRequest;
        try {
            //如果正确解析，就不再继续处理
            strictGson.fromJson(srcBodyJson, resolveParameterClass);

            // HttpHeader仍然要考虑处理
            try {
                // 尝试解析为HttpRequest对象
                httpRequest = gson.fromJson(srcBodyJson, HttpRequest.class);
                // 处理请求头
                processHttpHeader(httpRequest);
            } catch (RuntimeException e) {
                // 解析失败，继续处理
            }

            //虽然不作处理，但是流只能读取一次，所以需要重新构建
            return HttpRequestHttpInputMessage.of(srcBodyJson, inputMessage.getHeaders());
        } catch (JsonSyntaxException e) {
            // 解析失败，继续处理
        }
        // 解析为HttpRequest对象
        httpRequest = gson.fromJson(srcBodyJson, HttpRequest.class);

        // 处理参数
        String paramJson = processParam(httpRequest, strictGson, resolveParameterClass);

        // 处理请求头
        processHttpHeader(httpRequest);

        return HttpRequestHttpInputMessage.of(paramJson, inputMessage.getHeaders());
    }

    /**
     * 处理参数
     *
     * @param httpRequest
     * @param strictGson
     * @param targetType
     * @return
     */
    private String processParam(HttpRequest<?> httpRequest, Gson strictGson, Type targetType) {
        // 提取参数
        Object param = httpRequest.getParam();

        String paramJson = strictGson.toJson(param);

        // 严格解析Param
        try {
            strictGson.fromJson(paramJson, targetType);
        } catch (JsonSyntaxException e) {
            throw CommonException.of(e.getMessage());
        }
        return paramJson;
    }

    /**
     * 处理请求头
     *
     * @param httpRequest
     */
    private void processHttpHeader(HttpRequest<?> httpRequest) {
        // 提取header
        HttpHeader header = httpRequest.getHeader();
        // 放入线程上下文
        CommonRequestContextHolder.setHeader(header);

        // 获取当前请求的HttpServletRequest
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())
                .getRequest();
        // 放入请求属性缓存，用于参数解析器
        request.setAttribute("X-Http-Headers", header);
    }

    @Override
    public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
                                Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return body;
    }

    @Override
    public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
        return N.none();
    }
}